using System;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading;

using Coding4Fun.Maelstrom.Hardware.Diagnostics;

// based on http://forums.netduino.com/index.php?/topic/575-updated-web-server/
namespace Coding4Fun.Maelstrom.Hardware.WebServer
{
    public delegate void RequestReceivedHandler(Request request);

    public class Listener : IDisposable
    {
        const int MaxRequestSize = 1024;
        readonly int _portNumber = 80;

        private Socket _listeningSocket;

        public event RequestReceivedHandler RequestReceived;

        public Listener() : this(80) { }

        public Listener(int portNumber)
        {
            _portNumber = portNumber;
        }

        public void Start()
        {
            _listeningSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _listeningSocket.Bind(new IPEndPoint(IPAddress.Any, _portNumber));
            _listeningSocket.Listen(10);

            new Thread(StartListening).Start();
        }

        ~Listener()
        {
            Dispose();
        }

        private void StartListening()
        {

            while (true)
            {
                using (Socket clientSocket = _listeningSocket.Accept())
                {
					Logger.WriteLine("Received request from " + (clientSocket.RemoteEndPoint as IPEndPoint));

                    int bufferSize = (clientSocket.Available > MaxRequestSize) ? MaxRequestSize : clientSocket.Available;
					Logger.WriteLine(DateTime.Now + " " + bufferSize + " request bytes available");

					if (bufferSize > 0)
                    {
						var buffer = new byte[bufferSize];

						clientSocket.Receive(buffer, bufferSize, SocketFlags.None);

                        using (var r = new Request(clientSocket, Encoding.UTF8.GetChars(buffer)))
                        {
                            Logger.WriteLine(DateTime.Now + " " + r.Url);

                            if (RequestReceived != null)
								RequestReceived(r);
                        }
                    }
                }

                // I always like to have this in a continuous loop. Helps prevent lock-ups
                Thread.Sleep(5);
            }
        }

        #region IDisposable Members

        public void Dispose()
        {
            if (_listeningSocket != null)
				_listeningSocket.Close();
        }

        #endregion
    }
}
